home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / CMPLTPAS / JTERM.PAS < prev    next >
Pascal/Delphi Source File  |  1988-07-24  |  9KB  |  232 lines

  1. {--------------------------------------------------------------}
  2. {                         JTERM                                }
  3. {                                                              }
  4. {                             by Jeff Duntemann                }
  5. {                             Turbo Pascal V5.0                }
  6. {                             Last update 7/24/88              }
  7. {                                                              }
  8. { This is an interrupt-driven "dumb terminal" program for the  }
  9. { PC.  It illustrates the use of Turbo Pascal's INTERRUPT      }
  10. { procedures, and in a lesser fashion the use of serial port   }
  11. { hardware.  It is currently hardwired to COM1 for simplicity's}
  12. { sake.                                                        }
  13. {                                                              }
  14. {     From: COMPLETE TURBO PASCAL 5.0  by Jeff Duntemann       }
  15. {    Scott, Foresman & Co., Inc. 1988   ISBN 0-673-38355-5     }
  16. {--------------------------------------------------------------}
  17.  
  18.  
  19. PROGRAM JTerm;
  20.  
  21. USES DOS,CRT;
  22.  
  23.  
  24. CONST
  25.   COM1INT = 12;       { Vector # for COM1: (IRQ4) }
  26.  
  27.   { 8250 control registers, masks, etc. }
  28.   RBR      = $3F8;    { 8250 Receive Buffer Register     }
  29.   THR      = $3F8;    { 8250 Transmit Holding Register   }
  30.   LCR      = $3FB;    { 8250 Line Control Register       }
  31.   IER      = $3F9;    { 8250 Interrupt Enable Register   }
  32.   MCR      = $3FC;    { 8250 Modem Control Register      }
  33.   LSR      = $3FD;    { 8250 Line Status Register        }
  34.   DLL      = $3F8;    { 8250 Divisor Latch LSB           }
  35.   DLM      = $3F9;    { 8250 Divisor Latch MSB           }
  36.   DLAB     = $80;     { 8250 Divisor Latch Access Bit    }
  37.  
  38.  
  39.   BAUD300  = 384;     { Value for 300 baud operation     }
  40.   BAUD1200 = 96;      { Value for 1200 baud operation    }
  41.   NOPARITY = 0;       { Comm format value for no parity  }
  42.   BITS8    = $03;     { Comm format value for 8 bits     }
  43.   DTR      = $01;     { Value for Data Terminal Ready    }
  44.   RTS      = $02;     { value for Ready To Send          }
  45.   OUT2     = $08;     { Bit that enables adapter interrupts }
  46.  
  47.   { 8259 control registers, masks, etc. }
  48.   OCW1     = $21;     { 8259 Operation Control Word 1    }
  49.   OCW2     = $20;     { 8259 Operation Control Word 2    }
  50.   IRQ4     = $10;     { Mask to turn IRQ4 interrupts on/off }
  51.  
  52.  
  53.  
  54.  
  55. TYPE
  56.   CircularBuffer = ARRAY[0..1023] OF Char;  { A 1K input buffer }
  57.  
  58.  
  59. VAR
  60.   Quit       : Boolean;           { Flag for exiting the program }
  61.   HiBaud     : Boolean;           { True if 1200 baud is being used }
  62.   KeyChar    : Char;              { Character from keyboard }
  63.   CommChar   : Char;              { Character from the comm port }
  64.   Divisor    : Word;              { Divisor value for setting baud rate }
  65.   Clearit    : Byte;              { Dummy variable }
  66.   Buffer     : CircularBuffer;    { Our incoming character buffer }
  67.   LastRead,                       { Index of the last character read }
  68.   LastSaved  : Integer;           { Index of the last character stored }
  69.   NoShow     : SET OF Char;       { Don't show characters set }
  70.   OldVector  : Pointer;           { Global storage slot for the old }
  71.                                   { interrupt vector }
  72.  
  73.  
  74. {$I SHOWHELP.SRC}  { JTerm's minimal help system }
  75.  
  76.  
  77. PROCEDURE EnableInterrupts;
  78.  
  79. INLINE($FB);
  80.  
  81.  
  82.  
  83. {->>>>Incoming (Interrupt Service Routine)<<<<-----------------}
  84. {                                                              }
  85. { This is the ISR (interrupt Service Routine) for COM1.  Note: }
  86. { DO NOT call this routine directly; you'll crash hard.  The   }
  87. { only way Incoming takes control is when a character coming   }
  88. { in from the modem triggers a hardware interrupt from the     }
  89. { serial port chip, the 8250 UART.  Note that the register     }
  90. { pseudo-parameters are not needed here, and you could omit    }
  91. { them.  However, omitting them doesn't really get you any     }
  92. { more speed or reliability.                                   }
  93. {--------------------------------------------------------------}
  94.  
  95.  
  96. PROCEDURE Incoming(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : Word);
  97. INTERRUPT;
  98.  
  99. BEGIN
  100.   { Our first job is to enable interrupts during the ISR: }
  101.   EnableInterrupts;
  102.   { The first "real work" we do is either wrap or increment the index }
  103.   { of the last character saved.  If the index is "topped out" at     }
  104.   { 1023, we force it to zero.  This makes the 1024-byte buffer       }
  105.   { "circular," in that once the index hits the end, it rolls over to }
  106.   { the beginning again. }
  107.   IF LastSaved >= 1023 THEN LastSaved := 0 ELSE Inc(LastSaved);
  108.  
  109.   { Next, we read the actual incoming character from the serial port's}
  110.   { one-byte holding buffer: }
  111.   Buffer[LastSaved] := Char(Port[RBR]);
  112.  
  113.   { Finally, we must send a control byte to the 8259 interrupt  }
  114.   { controller, telling it that the interrupt is finished:      }
  115.   Port[OCW2] := $20;                    { Send EOI byte to 8259 }
  116. END;
  117.  
  118.  
  119.  
  120. {$F+}
  121. PROCEDURE JTermExitProc;
  122.  
  123. BEGIN
  124.   Port[IER] := 0;                      { Disable interrupts at 8250 }
  125.   Port[OCW1] := Port[OCW1] OR IRQ4;          { Disable IRQ4 at 8259 }
  126.   Port[MCR] := 0;                       { Bring the comm line down  }
  127.   SetIntVec(Com1Int,OldVector);   { Restore previously saved vector }
  128. END;
  129. {$F-}
  130.  
  131.  
  132.  
  133. PROCEDURE SetupSerialPort;
  134.  
  135. BEGIN
  136.   LastRead  := 0;  { Initialize the circular buffer pointers }
  137.   LastSaved := 0;
  138.  
  139.   Port[IER] := 0;  { Disable interrupts while we're setting them up }
  140.  
  141.   GetIntVec(Com1Int,OldVector);              { Save old IRQ4 vector }
  142.   ExitProc := @JTermExitProc;           { Hook exit proc into chain }
  143.   SetIntVec(Com1Int,@Incoming); { Put ISR address into vector table }
  144.  
  145.   Port[LCR] := Port[LCR] OR DLAB;  { Set up 8250 to set baud rate   }
  146.   Port[DLL] := Lo(Divisor);        { Set baud rate divisor          }
  147.   Port[DLM] := Hi(Divisor);
  148.   Port[LCR] := BITS8 OR NOPARITY;      { Set word length and parity }
  149.   Port[MCR] := DTR OR RTS OR OUT2;     { Enable adapter, DTR, & RTS }
  150.   Port[OCW1] := Port[OCW1] AND (NOT IRQ4); { Turn on 8259 IRQ4 ints }
  151.   Clearit := Port[RBR];                { Clear any garbage from RBR }
  152.   Clearit := Port[LSR];                { Clear any garbage from LSR }
  153.  
  154.   Port[IER] := $01;        { Enable interrupt on received character }
  155. END;
  156.  
  157.  
  158. FUNCTION InStat : Boolean;
  159.  
  160. BEGIN
  161.   IF LastSaved <> LastRead THEN InStat := True
  162.     ELSE InStat := False;
  163. END;
  164.  
  165.  
  166. FUNCTION InChar : Char;    { Bring in the next character }
  167.                            {   from the ring buffer }
  168. BEGIN
  169.   IF LastRead >= 1023 THEN LastRead := 0
  170.     ELSE LastRead := Succ(LastRead);
  171.   InChar := Buffer[LastRead];
  172. END;
  173.  
  174.  
  175. PROCEDURE OutChar(Ch : Char);   { Send a character to the comm port }
  176.  
  177. BEGIN
  178.   Port[THR] := Byte(Ch)     { Put character ito Transmit Holding Register }
  179. END;
  180.  
  181.  
  182. {>>>>>JTERM MAIN PROGRAM<<<<<}
  183.  
  184. BEGIN
  185.   HiBaud := True;               { JTerm defaults to 1200 baud; if "300"   }
  186.   Divisor := BAUD1200;          { is entered after "JTERM" on the command }
  187.   IF ParamCount > 0 THEN        { line, then 300 baud is used instead.    }
  188.     IF ParamStr(1) = '300' THEN
  189.       BEGIN
  190.         HiBaud := False;
  191.         Divisor := BAUD300
  192.       END;
  193.  
  194.   DirectVideo := True;
  195.   NoShow := [#0,#127];          { Don't display NUL or RUBOUT }
  196.   SetupSerialPort;              { Set up serial port & turn on interrupts }
  197.  
  198.  
  199.   ClrScr;
  200.   Writeln('>>>JTERM by Jeff Duntemann');
  201.  
  202.   Quit := False;        { Exit JTERM when Quit goes to True }
  203.   REPEAT
  204.  
  205.     IF InStat THEN      { If a character comes in from the modem }
  206.       BEGIN
  207.         CommChar := InChar;                        { Go get character  }
  208.         CommChar := Char(Byte(CommChar) AND $7F);  { Mask off high bit }
  209.         IF NOT (CommChar IN NoShow) THEN           { If we can show it,}
  210.           Write(CommChar)                          {  then show it! }
  211.       END;
  212.  
  213.     IF KeyPressed THEN  { If a character is typed at the keyboard }
  214.       BEGIN
  215.         KeyChar := ReadKey;       { First, read the keystroke }
  216.         IF KeyChar = Chr(0) THEN  { We have an extended scan code here }
  217.           BEGIN
  218.             KeyChar := ReadKey;   { Read second half of extended code  }
  219.             CASE Ord(KeyChar) OF
  220.              59 : ShowHelp;       { F1 : Display help screen }
  221.             END { CASE }
  222.           END
  223.         ELSE
  224.         CASE Ord(KeyChar) OF
  225.          24 : Quit := True;   { Ctrl-X: Exit JTerm }
  226.          26 : ClrScr;         { Ctrl-Z: Clear the screen }
  227.          ELSE OutChar(KeyChar)
  228.         END;  { CASE }
  229.       END
  230.  
  231.   UNTIL Quit
  232. END.